/**
 * @(#)HibernatePersistenceDelegate.java 19/03/2010
 *
 * Copyright (c) 2005-2010 PsiqueWare S.A. de C.V. All Rights Reserved.
 * This software is the proprietary information PsiqueWare S.A. de C.V.
 * Use is subject to license terms.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * <br/>Usuario : AngelElectrico
 * <br/>Creaci&oacute;n: 19/03/2010 - 11:07:38 AM
 * <br/>
 * <br/>
 * <br/><t5>Cambios :</t5>
 * <br/><b>Fecha | Autor  |  Cambios</b>
 * <ul>
 * <li>19/03/2010 | <a href = "mailto:AngelElectrico@PsiqueWare.com">&Aacute;ngel El&eacute;ctrico</a> | Creaci&oacute;n del Objeto.</li>
 *
 * </ul>
 */

package com.psiqueware.alheli.dao.hibernate;

import org.hibernate.mapping.Bag;

import java.beans.DefaultPersistenceDelegate;
import java.beans.Encoder;
import java.beans.Expression;
import java.util.*;

/**
 * {@link PersistenceDelegate} necesario para utilizar clases de hibernate
 * <p/>
 * <br/>Paquete Original: com.psiqueware.alheli.dao.hibernate
 * <br/>Nombre  Original: HibernatePersistenceDelegate
 * <br/>Oprima para ver : <a href="HibernatePersistenceDelegate.java.html"><i>C&oacute;digo Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">AngelElectrico</a>
 * @version Revision: 1.1 19/03/2010 11:07:38 AM
 * @noinspection unchecked
 */
public final class HibernatePersistenceDelegate extends DefaultPersistenceDelegate
{

    private static final Map CLASS_MAP;

    static
    {
        final HashMap map = new HashMap();
        map.put(Bag.class, ArrayList.class);
        map.put(org.hibernate.mapping.IdentifierBag.class, ArrayList.class);
        map.put(org.hibernate.mapping.List.class, ArrayList.class);
        map.put(org.hibernate.mapping.Map.class, HashMap.class);
        map.put(org.hibernate.mapping.Set.class, HashSet.class);
        map.put(SortedMap.class, TreeMap.class);
        map.put(SortedSet.class, TreeSet.class);
        CLASS_MAP = Collections.synchronizedMap(map);
    }

    private static final Map SECONDARY_CLASS_MAP;

    static
    {
        final HashMap map = new HashMap();
        map.put(org.hibernate.mapping.List.class, List.class);
        map.put(org.hibernate.mapping.Map.class, Map.class);
        map.put(org.hibernate.mapping.Set.class, Set.class);
        SECONDARY_CLASS_MAP = map;
    }

    private static HibernatePersistenceDelegate INSTANCE = new HibernatePersistenceDelegate();

    private HibernatePersistenceDelegate()
    {
    }


    /**
     * Get the set of delegates to install in an
     * {@link java.beans.Encoder Encoder}
     * to properly handle Hibernate collections types. This method returns
     * the set as a mapping from {@link Class} -&gt;
     * {@link PersistenceDelegate}.
     */
    public static Map getDelegates()
    {
        HashMap map = new HashMap();
        for (Iterator i = CLASS_MAP.keySet().iterator(); i.hasNext(); )
        {
            map.put(i.next(), INSTANCE);
        }
        return map;
    }

    /**
     * Clases that are delegated.
     *
     * @return {@link Map} of {@link Class} that are delegated.
     */
    public static Map<Class, Class> getDelegatedClasses()
    {
        return CLASS_MAP;
    }

    /**
     * Clases that are delegated, secondary set.
     *
     * @return {@link Map} of {@link Class} that are delegated.
     */
    public static Map<Class, Class> getSecondaryDelegatedClasses()
    {
        return SECONDARY_CLASS_MAP;
    }

    /**
     * Overridden to handle conversion of Hibernate collection
     * classes into {@link java.util} collection classes.
     */
    protected Expression instantiate(Object oldInstance, Encoder out)
    {
        Class replaceType = (Class) CLASS_MAP.get(oldInstance.getClass());
        if (replaceType != null)
        {
            return new Expression(oldInstance, replaceType, "new", new Object[0]);
        }
        return super.instantiate(oldInstance, out);
    }

    /**
     * Overridden to handle conversion of Hibernate collection
     * classes into {@link java.util} collection classes.
     */
    protected boolean mutatesTo(Object oldInstance, Object newInstance)
    {
        return oldInstance != null && newInstance != null && CLASS_MAP.get(oldInstance.getClass()) == newInstance.getClass() || super.mutatesTo(oldInstance, newInstance);
    }

    /**
     * Overridden to handle conversion of Hibernate collection
     * classes into {@link java.util} collection classes.
     */
    protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out)
    {
        Class replaceType = (Class) CLASS_MAP.get(oldInstance.getClass());
        if (replaceType != null)
        {
            Object replace = replace(oldInstance);
            if (type == oldInstance.getClass()) type = replace.getClass();
            super.initialize(type, replace, newInstance, out);
        }
        super.initialize(type, oldInstance, newInstance, out);
    }

    /**
     * @noinspection unchecked
     */
    private Object replace(Object obj)
    {
        if (obj instanceof org.hibernate.mapping.Set) return new HashSet((Set) obj);
        else if (obj instanceof org.hibernate.mapping.Map) return new HashMap((Map) obj);
        else if (obj instanceof SortedSet) return new TreeSet((SortedSet) obj);
        else if (obj instanceof SortedMap) return new TreeMap((SortedMap) obj);
        else if (obj instanceof org.hibernate.mapping.List || obj instanceof org.hibernate.mapping.Bag || obj instanceof org.hibernate.mapping.IdentifierBag)
            return new ArrayList((Collection) obj);
        throw new RuntimeException("unexpected");
    }


}

